VS2019+PCL+LAS点云学习
2023/10/12 10:52:02
VS2019+PCL+LAS点云学习教程、基本代码
部分教程汇总
安装教程
- win10系统下 VS2019点云库PCL1.12.0的安装与配置:https://blog.csdn.net/Nelson_Leo/article/details/118600787
- PCL点云库安装及学习(2021.7.28):https://blog.csdn.net/jing_zhong/article/details/118696089
- PCL安装教程(Win10+vs2019+PCL1.10.1):https://blog.csdn.net/weixin_43403569/article/details/118568577
- VS2019+pcl1.12.1配置详解:https://blog.csdn.net/biubiubiu011/article/details/127160201
- Gitee上传、更新仓库代码:https://blog.csdn.net/qq_38697586/article/details/128185549
其他教程
pcl生成三个点连线,画箭头,画圆,改线条颜色:https://blog.csdn.net/qq_41092406/article/details/114041229
计算空间中点到直线的距离:https://blog.csdn.net/qq_37220275/article/details/117954824
三维空间的直线方程:https://blog.csdn.net/qq_39706570/article/details/105962373
已经两点求直线方程(多维空间):https://www.cnblogs.com/yaolin1228/p/7871793.html
PCL生成线段点云:https://blog.csdn.net/Dbojuedzw/article/details/126127391
【计算几何】多边形点集排序:https://www.cnblogs.com/dwdxdy/p/3230156.html
空间点到直线垂足坐标的解算方法:https://blog.csdn.net/zhouschina/article/details/14647587
pcl::compute3DCentroid()计算质心算法原理:
PCL:点云赋色 | 自定义点云中任意一点的颜色:http://www.taodudu.cc/news/show-3123035.html
PCL C++版【学习备忘】:https://blog.csdn.net/expert_joe/article/details/123342098
点云入门
功能示例代码段
1. pcl::PointCloud数据类型
- 点云类型
// 点云指针类型
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudPtr (new pcl::PointCloud<pcl::PointXYZ>);
// 点云对象
pcl::PointCloud<pcl::PointXYZ> cloud;
// 单个点云的点
pcl::PointXYZ point;
- 访问形式
// 访问第一个点的x
cloud.points[0].x;
cloudPtr->points[0].x;
// 访问单个点的x
point.x;
2. 从点云里删除点和添加点
- 点云增删改查
#include <pcl/io/pcd_io.h>
#include <pcl/common/impl/io.hpp>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
int main(int argc, char **argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile<pcl::PointXYZ>("bun0.pcd", *cloud);
pcl::PointCloud<pcl::PointXYZ>::iterator index = cloud->begin();
// 删除点
cloud->erase(index);//删除第一个
index = cloud->begin() + 5;
cloud->erase(cloud->begin());//删除第5个
pcl::PointXYZ point = { 1, 1, 1 };
// 添加点
//在索引号为5的位置1上插入一点,原来的点后移一位
cloud->insert(cloud->begin() + 5, point);
cloud->push_back(point);//从点云最后面插入一点
std::cout << cloud->points[5].x;//输出1
}
3. 新建一个点云对象,然后对点云对象进行初始化,并随机赋值
- 初始化点云
pcl::PointCloud<pcl::PointXYZ> cloud;
// 创建点云
cloud.width=5;
cloud.height=1;
cloud.is_dense=false;
cloud.points.resize(cloud.width*cloud.height);
// 随机赋值
for(size_t i=0;i<cloud.points.size();++i)
{
cloud.points[i].x=1024*rand()/(RAND_MAX+1.0f);
cloud.points[i].y=1024*rand()/(RAND_MAX+1.0f);
cloud.points[i].z=1024*rand()/(RAND_MAX+1.0f);
}
// 将点云保存为pcd文件
pcl::io::savePCDFileASCII("test_pcd.pcd",cloud);
4. 点云可视化基本操作
- PCLVisualizer
// 定义一个显示器
pcl::visualization::PCLVisualizer viewer("registration Viewer");
// 给点云定义一个颜色 RGB模式 为全G 绿色
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(cloud, 0, 200, 200);
// 设置背景颜色 255,255,255就是白色
viewer.setBackgroundColor(255, 255, 255);
// 把点云加入到显示器里
viewer.addPointCloud(cloud, "source cloud");
- 点云视窗类:CloudViewer
// 创建viewer对象
pcl::visualization::CloudViewer viewer("Cloud Viewer");
// 加载点云
viewer.showCloud(cloud);
5. 点的顺时针、逆时针排序
- 顺时针
//若点a大于点b,即点a在点b顺时针方向,返回true,否则返回false
bool PointCmp(const pcl::PointXYZ a, const pcl::PointXYZ b, const pcl::PointXYZ center)
{
if (a.x >= 0 && b.x < 0)
return true;
if (a.x == 0 && b.x == 0)
return a.y > b.y;
//向量OA和向量OB的叉积
float det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);
if (det < 0)
return true;
if (det > 0)
return false;
//向量OA和向量OB共线,以距离判断大小
float d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y);
float d2 = (b.x - center.x) * (b.x - center.y) + (b.y - center.y) * (b.y - center.y);
return d1 > d2;
}
//点集合
void sortClockwise(pcl::PointXYZ vPoints[], int n)
{
//计算重心
pcl::PointXYZ center;
double x = 0, y = 0, z = 0;
for (int i = 0; i < n; i++)
{
x += vPoints[i].x;
y += vPoints[i].y;
z += vPoints[i].z;
}
center.x = x / n;
center.y = y / n;
center.z = z / n;
cout << "center:" << center.x << "," << center.y << "," << center.z << endl;
//冒泡排序
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (PointCmp(vPoints[j], vPoints[j + 1], center))
std::swap(vPoints[j], vPoints[j + 1]);
}
}
//return vPoints;
}
- 逆时针、顺时针
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/centroid.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/geometry/planar_polygon.h>//定义多边形
// 逆时针排序
void CounterClockWiseSortPoints(pcl::PointCloud<pcl::PointXYZ>& vPoints)
{
int cnt = static_cast<int>(vPoints.size());
if (cnt < 3)
return;
//计算中心
Eigen::Vector4f centroid; // 质心
pcl::compute3DCentroid(vPoints, centroid); // 齐次坐标,(c0,c1,c2,1)
pcl::PointXYZ center{ centroid[0],centroid[1] ,centroid[2] };
//若点a小于点b,即点a在点b逆时针方向,返回true,否则返回false
auto PointCmp = [](const pcl::PointXYZ& a, const pcl::PointXYZ& b, const pcl::PointXYZ& center)
{
if (a.x <= 0 && b.x > 0)
return true;
if (a.x == 0 && b.x == 0)
return a.y < b.y;
//向量OA和向量OB的叉积,向量OA和OB的叉积大于0,则向量OA在向量OB的逆时针方向,即点A小于点B。
float det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);
if (det < 0)
return false;
if (det > 0)
return true;
//向量OA和向量OB共线,以距离判断大小
float d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y);
float d2 = (b.x - center.x) * (b.x - center.y) + (b.y - center.y) * (b.y - center.y);
return d1 > d2;
};
//冒泡排序
for (int i = 0; i < cnt - 1; i++)
{
for (int j = 0; j < cnt - i - 1; j++)
{
if (PointCmp(vPoints[j], vPoints[j + 1], center))
std::swap(vPoints[j], vPoints[j + 1]);
}
}
}
// 顺时针排序
void ClockWiseSortPoints(pcl::PointCloud<pcl::PointXYZ>& vPoints)
{
int cnt = static_cast<int>(vPoints.size());
if (cnt < 3)
return;
//计算中心
Eigen::Vector4f centroid; // 质心
pcl::compute3DCentroid(vPoints, centroid); // 齐次坐标,(c0,c1,c2,1)
pcl::PointXYZ center{ centroid[0],centroid[1] ,centroid[2] };
//若点a大于点b,即点a在点b顺时针方向,返回true,否则返回false
auto PointCmp = [](const pcl::PointXYZ& a, const pcl::PointXYZ& b, const pcl::PointXYZ& center)
{
if (a.x >= 0 && b.x < 0)
return true;
if (a.x == 0 && b.x == 0)
return a.y > b.y;
//向量OA和向量OB的叉积,向量OA和OB的叉积大于0,则向量OA在向量OB的逆时针方向,即点A小于点B。
float det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);
if (det < 0)
return false;
if (det > 0)
return true;
//向量OA和向量OB共线,以距离判断大小
float d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y);
float d2 = (b.x - center.x) * (b.x - center.y) + (b.y - center.y) * (b.y - center.y);
return d1 > d2;
};
//冒泡排序
for (int i = 0; i < cnt - 1; i++)
{
for (int j = 0; j < cnt - i - 1; j++)
{
if (PointCmp(vPoints[j], vPoints[j + 1], center))
std::swap(vPoints[j], vPoints[j + 1]);
}
}
}
int main(int argc, char** argv)
{
//--------------------------加载点云数据----------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PCDReader reader;
reader.read("排序.pcd", *cloud);
std::cerr << "原始点云点的个数: " << cloud->points.size() << std::endl;
ClockWiseSortPoints(*cloud);
//CounterClockWiseSortPoints(*cloud); // 逆时针排序
//增加多边形
pcl::PlanarPolygon<pcl::PointXYZ> polygon;
pcl::PointCloud<pcl::PointXYZ> contour;
contour.width = cloud->width;
contour.height = 1;
contour.is_dense = false;
contour.resize(contour.height * contour.width);
for (size_t i = 0; i < cloud->points.size(); ++i)
{
cout << "第" << i << "个点的坐标为" << cloud->points[i] << endl;
contour.points[i] = cloud->points[i];
}
polygon.setContour(contour);
pcl::io::savePCDFileASCII("顺时针排列.pcd", *cloud);
pcl::visualization::PCLVisualizer viewer("Viewer");
viewer.setWindowName("平面点云边界点排序");
viewer.addPolygon(polygon, 255, 0, 0, "ploygon", 0);
viewer.addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "sample cloud"); // 设置点云大
while (!viewer.wasStopped())
{
viewer.spinOnce(1);
}
return 0;
}
6. 点云合并
// Objects for storing the point clouds.
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloudA(new pcl::PointCloud<pcl::PointXYZRGBA>);
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloudB(new pcl::PointCloud<pcl::PointXYZRGBA>);
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloudC(new pcl::PointCloud<pcl::PointXYZRGBA>);
// 读取两个点云文件
if (pcl::io::loadPLYFile<pcl::PointXYZRGBA>("C:\\Users\\fhlhc\\Desktop\\left.ply", *cloudA) != 0)
{
return -1;
}
if (pcl::io::loadPLYFile<pcl::PointXYZRGBA>("C:\\Users\\fhlhc\\Desktop\\right.ply", *cloudB) != 0)
{
return -1;
}
// Create cloud "C", with the points of both "A" and "B".点云A、B合并生成C
*cloudC = (*cloudA) + (*cloudB);
// Now cloudC->points.size() equals cloudA->points.size() + cloudB->points.size().
//可视化
pcl::visualization::PCLVisualizer viewer("合并两个点云");
7. 通过某点对空间直线做垂线,求垂足
pcl::PointXYZ GetFootOfPerpendicular(
const pcl::PointXYZ pt, // 直线外一点
const pcl::PointXYZ begin, // 直线开始点
const pcl::PointXYZ end) // 直线结束点
{
pcl::PointXYZ retVal;
double dx = begin.x - end.x;
double dy = begin.y - end.y;
double dz = begin.z - end.z;
if (abs(dx) < 0.00000001 && abs(dy) < 0.00000001 && abs(dz) < 0.00000001)
{
retVal = begin;
return retVal;
}
double u = (pt.x - begin.x) * (begin.x - end.x) + (pt.y - begin.y) * (begin.y - end.y) + (pt.z - begin.z) * (begin.z - end.z);
u = u / ((dx * dx) + (dy * dy) + (dz * dz));
retVal.x = begin.x + u * dx;
retVal.y = begin.y + u * dy;
retVal.z = begin.z + u * dz;
return retVal;
}